import asyncio
import logging
import datetime
import builtins
import threading
import x_com_lib

class Context:
  request_id: int
  channel_id: int
  conn_id: int
  sender_service_key: x_com_lib.PyServiceKey
  from_addr: str

# 解析参数
class MillisecondFormatter(logging.Formatter):
    def format(self, record):
        s = super().format(record)
        old_time = self.formatTime(record, self.datefmt)
        new_time = datetime.datetime.fromtimestamp(record.created).strftime('%Y-%m-%d %H:%M:%S.{:03d}'.format(int(record.msecs)))
        return s.replace(old_time, new_time)

class XportLogHandler(logging.Handler):
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    format_str = '%(asctime)s  %(levelname)s {} %(filename)s %(lineno)d: %(message)s'.format(x_com_lib.dxc_name())
    self.formatter = MillisecondFormatter(format_str)
  def emit(self, record):
    log_entry = self.format(record)
    x_com_lib.log.output(log_entry)


def init():
  TRACE_LEVEL_NUM = 5
  logging.addLevelName(TRACE_LEVEL_NUM, "TRACE")
  def trace(self, message, *args, **kws):
      if self.isEnabledFor(TRACE_LEVEL_NUM):
          self._log(TRACE_LEVEL_NUM, message, args, **kws)
  #
  logging.Logger.trace = trace
  logger = logging.getLogger('xport')
  log_level = x_com_lib.log.level().upper()
  # 
  if log_level == "TRACE":
    logger.setLevel(TRACE_LEVEL_NUM)
  elif log_level == "DEBUG":
    logger.setLevel(logging.DEBUG)
  elif log_level == "INFO":
    logger.setLevel(logging.INFO)
  elif log_level == "WARN":
    logger.setLevel(logging.WARNING)
  elif log_level == "ERROR": 
    logger.setLevel(logging.ERROR) 
  # 
  xport_log_handler = XportLogHandler()
  logger.addHandler(xport_log_handler)
  builtins.logger = logger
  import subscribe
  builtins.subscribe = subscribe
def getLogger() -> logging.Logger:
  return builtins.logger

def check_stop_event():
  if x_com_lib.is_exit() or builtins.is_exit:
    builtins.is_exit = True
    builtins.loop.stop()
  else:
    # 每秒检查一次
    builtins.loop.call_later(1, check_stop_event)

def run_loop_in_thread():
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    builtins.loop = loop
    loop.call_soon(check_stop_event)
    loop.run_forever()

def dispatch_message(dxc_header, msg, param):
  builtins.loop.call_soon_threadsafe(lambda: builtins.loop.create_task(_inner_dispatch_message(dxc_header, msg, param)))

async def lanuch():
  builtins.is_exit = False
  thread = threading.Thread(target=run_loop_in_thread)
  thread.start()
  init() 
  await x_com_lib.init()
  try:
    while not builtins.is_exit:
      await asyncio.sleep(1) 
  except:
    builtins.is_exit = True


async def _inner_dispatch_message(dxc_header, msg, param):
  ctx = Context()
  ctx.request_id = dxc_header.request_id
  ctx.channel_id = dxc_header.channel_id
  ctx.conn_id = dxc_header.conn_id
  if hasattr(dxc_header, "from_addr"):
    ctx.from_addr = dxc_header.from_addr
  ctx.sender_service_key = dxc_header.sender_key
  try:
      # 4 == MsgType::Stream
      if dxc_header.msg_type == 4:
          if ctx.sender_service_key.dxc_name == "RealtimeKdataService":
            if msg == "RtTickData":
              await builtins.subscribe.realtime_kdata_service.rt_tick_data(ctx, param)
      elif msg == "on_init":
        await builtins.SERVICE.on_init()
        x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 0, "", None)
      elif msg == "SubscribeRtData":
        ret = await builtins.SERVICE.subscribe_rt_data(ctx, param)
        x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 0, "", ret)
      elif msg == "CancelSubscribeRtData":
        ret = await builtins.SERVICE.cancel_subscribe_rt_data(ctx, param)
        x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 0, "", ret)
      elif msg == "GetRtMinData":
        ret = await builtins.SERVICE.get_rt_min_data(ctx, param)
        x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 0, "", ret)
      elif msg == "ClearMinData":
        ret = await builtins.SERVICE.clear_min_data(ctx, param)
        x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 0, "", ret)
      elif msg == "SearchCode":
        ret = await builtins.SERVICE.search_code(ctx, param)
        x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 0, "", ret)
      elif msg == "FindData":
        ret = await builtins.SERVICE.find_data(ctx, param)
        x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 0, "", ret)
      elif msg == "on_finalize":
        await builtins.SERVICE.on_finalize()
        x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 0, "", None)
      else:
        builtins.logger.warn("无该 {} 消息的处理函数".format(msg))
  except Exception as e:
    x_com_lib.xport.response_message(dxc_header.request_id, dxc_header.sender_key, msg, 1, str(e), None)
